Skip to content

feat(kona): execute NUT bundles at Karst fork activation#20157

Open
maurelian wants to merge 18 commits intodevelopfrom
feat-kona-nut-execution
Open

feat(kona): execute NUT bundles at Karst fork activation#20157
maurelian wants to merge 18 commits intodevelopfrom
feat-kona-nut-execution

Conversation

@maurelian
Copy link
Copy Markdown
Contributor

@maurelian maurelian commented Apr 18, 2026

Summary

Wires Karst NUT bundle execution into kona-node's payload derivation, matching op-node's behavior.

  • kona-hardforks gets a build.rs that reads op-core/nuts/bundles/karst_nut_bundle.json at compile time and emits Rust code constructing the NutBundle — keeps the crate no_std and serde-free at runtime.
  • The Hardfork trait grows upgrade_gas(); the stateful attributes builder adds that gas to the block gas limit when Karst activates, so upgrade transactions have headroom.
  • Test in forks.rs updated from len() == 0 to len() == 32 to reflect the populated bundle.
  • TestActivationBlockNUTBundle in op-e2e/actions/proofs/ verifies activation block contents generically: discovery runs through forks.All + derive.UpgradeTransactions, so any future fork that ships a NUT bundle is covered without test changes.

Test plan

  • cargo nextest run in rust/kona — 119 passed
  • test_karst_upgrade_txs asserts 32 transactions
  • test_karst_upgrade_gas asserts 51_600_000 gas
  • TestActivationBlockNUTBundle/karst compiles + vets clean locally (full run needs forge artifacts — CI)

Closes #20239
Closes #20144

@maurelian maurelian requested a review from a team as a code owner April 18, 2026 14:59
@wiz-0f98cca50a
Copy link
Copy Markdown

wiz-0f98cca50a Bot commented Apr 18, 2026

Wiz Scan Summary

Scanner Findings
Vulnerability Finding Vulnerabilities 7 High 1 Medium 5 Low
Data Finding Sensitive Data -
Secret Finding Secrets -
IaC Misconfiguration IaC Misconfigurations 1 Medium
SAST Finding SAST Findings -
Software Management Finding Software Management Findings -
Total 7 High 2 Medium 5 Low

View scan details in Wiz

To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 18, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.3%. Comparing base (befabab) to head (1a1b24f).
⚠️ Report is 57 commits behind head on develop.

❗ There is a different number of reports uploaded between BASE (befabab) and HEAD (1a1b24f). Click for more details.

HEAD has 14 uploads less than BASE
Flag BASE (befabab) HEAD (1a1b24f)
contracts-bedrock-tests 12 0
unit 2 0
Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #20157      +/-   ##
===========================================
- Coverage     76.6%    66.3%   -10.3%     
===========================================
  Files          691       55     -636     
  Lines        76081     4035   -72046     
===========================================
- Hits         58298     2677   -55621     
+ Misses       17639     1214   -16425     
  Partials       144      144              
Flag Coverage Δ
cannon-go-tests-64 66.3% <ø> (ø)
contracts-bedrock-tests ?
unit ?

Flags with carried forward coverage won't be shown. Click here to find out more.
see 636 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@maurelian maurelian force-pushed the feat-kona-nut-execution branch from c38d430 to 0a41e7d Compare April 20, 2026 14:14
@maurelian maurelian marked this pull request as draft April 20, 2026 14:25
maurelian added 2 commits April 20, 2026 17:01
Add build.rs that reads karst_nut_bundle.json at compile time and
generates Rust code to construct the NutBundle. The derive pipeline
now adds upgrade gas to the block gas limit at fork activation,
matching op-node's gas accounting behavior.
Verifies that every fork with an embedded NUT bundle produces an
activation block containing exactly the bundle's deposit transactions.
Discovery uses forks.All + derive.UpgradeTransactions, so future forks
with NUT bundles are covered automatically without test changes.
@maurelian maurelian force-pushed the feat-kona-nut-execution branch from 0a41e7d to df9aabf Compare April 20, 2026 21:06
Comment thread rust/kona/crates/protocol/hardforks/build.rs Outdated
Comment thread op-e2e/actions/proofs/nut_bundle_activation_test.go Outdated
Comment thread rust/kona/crates/protocol/hardforks/build.rs Outdated
Comment thread rust/kona/crates/protocol/hardforks/build.rs Outdated
Comment thread rust/kona/crates/protocol/hardforks/build.rs
Comment thread rust/kona/crates/protocol/hardforks/build.rs Outdated
Comment thread rust/kona/crates/protocol/hardforks/src/karst.rs Outdated
Comment thread ops/scripts/check-nut-locks/main.go Outdated
Comment thread op-e2e/actions/proofs/nut_bundle_activation_test.go
Comment thread op-e2e/actions/proofs/nut_bundle_activation_test.go
@maurelian maurelian force-pushed the feat-kona-nut-execution branch from 941e15a to caf98bb Compare April 21, 2026 18:32
Comment thread rust/kona/docker/apps/kona_app_generic.dockerfile
maurelian added 3 commits April 21, 2026 14:41
The Docker build context for kona images is scoped to rust/, so build.rs
cannot reach op-core/nuts/bundles/ via ancestor walk and the kona-client/
host/node images fail to build. Keep a byte-identical copy inside the
crate, written and verified automatically by the existing snapshot/lock
tooling so the two sources cannot silently drift.
The kona-hardforks build.rs walks ancestors of CARGO_MANIFEST_DIR to find
op-core/nuts/bundles/ during compilation. The kona-{client,host,node}
images scope their Docker context to rust/, so the ancestor walk can't
reach op-core/ and the images fail to build.

Pass op-core/nuts/bundles as an additional named BuildKit context
(nuts-bundles) and copy it into /workspace/op-core/nuts/bundles so the
ancestor walk succeeds. Keeps the primary rust/ context small and avoids
mirroring the bundle JSON into the crate tree.
@maurelian maurelian force-pushed the feat-kona-nut-execution branch from caf98bb to 815bf97 Compare April 21, 2026 18:41
maurelian added 4 commits April 21, 2026 14:45
Iterate forks.From(forks.Karst) with a NoError assertion on
derive.UpgradeTransactions rather than silently skipping forks whose
bundle fails to load, so a broken bundle surfaces as a test failure.

Also assert every tx in the activation block has a successful receipt
so a reverted upgrade tx can't hide behind the byte-equality check.
The Hardfork impl for each NUT-bundle-backed fork is identical boilerplate
(decode, EIP-2718 encode, sum gas). Move that pattern into a single
internal macro so adding future forks is a one-liner next to the
build-script-generated constructor.
Split parsing + codegen into build_helpers.rs, included via #[path] from
both the build script and a new integration test. Use anyhow to carry
error context up to a single panic in main. The integration test runs
the generator on a fixture JSON and asserts the exact Rust source output,
so codegen changes surface as a test failure rather than a downstream
compile error.
Follows the per-fork test convention from ecotone/fjord/isthmus/holocene.
Asserts the EIP-1967 implementation slot of representative predeploy
proxies (L1Block, GasPriceOracle) changes across Karst activation — a
Karst-specific smoke test that the bundle's proxy upgrades took effect.

Not generalized into the NUT bundle activation test because it does not
hold for future forks that may not upgrade proxies.
Comment thread rust/kona/crates/protocol/hardforks/build.rs
Comment thread rust/kona/crates/protocol/hardforks/src/nut_bundle.rs
Comment thread op-e2e/actions/proofs/nut_bundle_activation_test.go
Comment thread op-e2e/actions/proofs/karst_fork_test.go Outdated
Comment thread op-e2e/actions/proofs/karst_fork_test.go Outdated
Comment thread op-e2e/actions/proofs/nut_bundle_activation_test.go Outdated
Comment thread op-e2e/actions/proofs/nut_bundle_activation_test.go Outdated
@maurelian maurelian marked this pull request as ready for review April 22, 2026 13:34
maurelian added 2 commits April 22, 2026 14:46
Share the initialization between the next/prev maps and replace the
manual forks.All index walk in nut_bundle_activation_test.go with
forks.Prev(fork). Keeps neighbor-navigation centralized in the forks
package rather than re-derived at call sites.
The generic activation test was missing the core RunFaultProofProgram
call (preceded by BatchMineAndSync to advance the safe head), so it
only exercised the sequencer, not the proof pipeline it lives under
actions/proofs/ to validate.

Fold the Karst-specific impl-slot assertions back in via a switch on
fork name, establishing the pattern for future forks to register their
own post-activation checks alongside the universal ones. Delete
karst_fork_test.go.
Comment thread op-e2e/actions/proofs/nut_bundle_activation_test.go Outdated
Comment thread op-core/forks/forks.go
Comment thread op-e2e/actions/proofs/nut_bundle_activation_test.go Outdated
Use RollupCfg.IsActivationBlockForFork instead of the unguarded
IsActivationBlock(time-blockTime, time) — the helper avoids a uint64
underflow when actHeader.Time < blockTime.

Assert the safe head lands exactly on the activation block rather than
just past it; BatchMineAndSync adds no new L2 blocks, so equality is
the right invariant.
maurelian added 4 commits April 23, 2026 16:25
Table-driven coverage of edge cases (first, middle, last, unknown)
plus a NextPrev/PrevNext inverse check that guards against the two
maps drifting out of sync.
Generated bundle constructors now wrap construction in a function-scoped
once_cell::sync::OnceCell and return &'static NutBundle. The first call
allocates and stores the bundle; subsequent calls return a cached
reference. Activation-path calls to txs() and upgrade_gas() no longer
reallocate on each invocation.

Consumers are unchanged — method calls auto-deref through the reference.
cargo fmt -- collapses a few multi-line statements onto one line per
the use_small_heuristics = "Max" rustfmt.toml setting.

cargo clippy -- replaces a match-on-Option in the bundle codegen with
Option::map_or_else per the option_if_let_else lint.
The cannon-repro.dockerfile's client-build stage runs cargo build on the
kona workspace, which triggers the kona-hardforks build script. That
script walks ancestors of CARGO_MANIFEST_DIR looking for op-core/ and
panicked because the context only contained kona/. Pull in
op-core/nuts/bundles from the existing 'monorepo' named context so the
ancestor walk succeeds — same pattern as the kona-node/host/client
image fix.
Comment thread rust/kona/docker/fpvm-prestates/cannon-repro.dockerfile
maurelian added 2 commits April 24, 2026 16:29
- stateful.rs: collapse the u64::from_be_bytes call onto one line per
  nightly rustfmt's use_small_heuristics = "Max" setting. Introduced
  by the original Karst upgrade_gas change; caught by rust-fmt CI.
- nut_bundle_activation_test.go: use bigs.Uint64Strict(bigInt) instead
  of bigInt.Uint64() per the repo's bigint custom golangci-lint rule.
sync::OnceCell with the critical-section feature requires an impl of
_critical_section_1_0_{acquire,release} to be linked in, which the
MIPS64 cannon and RISC-V asterisc fault-proof VM targets don't provide.
This broke kona-client on those targets.

Switch the generator to emit once_cell::race::OnceBox, which uses a
single AtomicPtr for the cache slot — lock-free and requires no
critical-section impl. The NutBundle is heap-allocated via Box on first
call and then cached as &'static NutBundle for all subsequent calls.
Enables the `race` feature on once_cell.
@ethereum-optimism ethereum-optimism deleted a comment from optibotpiper Bot Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[L2CM] Kona NUT execution at karst fork [L2CM] Add Karst fork action test

3 participants